package me.qi.kancha.security.authorities;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import me.qi.kancha.dto.core.EntityAccountDTO;
import me.qi.kancha.service.EntityAccountService;
import com.xhyt.common.resource.support.PermitObject;
import com.xhyt.common.resource.support.TokenPrincipal;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 权限增强型tokenService,继承defaultTokenService,重写了ResourceServerTokenServices相关方法
 *
 * @author sun
 * @date 2022/1/19 15:16
 * @modified By：
 */
@Component
public class AuthoritiesEnhanceTokenService extends DefaultTokenServices {

    private final PermitService permitService;

    private final EntityAccountService entityAccountService;

    public AuthoritiesEnhanceTokenService(TokenStore tokenStore, PermitService permitService,
                                          TokenEnhancer tokenEnhancer, ClientDetailsService clientDetailsService, EntityAccountService entityAccountService) {
        this.permitService = permitService;
        this.entityAccountService = entityAccountService;
        super.setTokenStore(tokenStore);
        super.setTokenEnhancer(tokenEnhancer);
        super.setClientDetailsService(clientDetailsService);
    }

    @Override
    public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException, InvalidTokenException {
        //从token里获得的信息
        OAuth2Authentication oAuth2Authentication = super.loadAuthentication(accessTokenValue);
        OAuth2Request request = oAuth2Authentication.getOAuth2Request();
        Authentication userAuthentication = oAuth2Authentication.getUserAuthentication();
        //获取权限信息
        String aid = "client_credentials".equals(request.getGrantType()) ? null
                : (String) ((TokenPrincipal) userAuthentication.getPrincipal()).getPrincipal().get("aid");
        List<PermitObject> list = permitService.getPermit(request.getClientId(), request.getGrantType(), aid);
        //重新构建 OAuth2Authentication
        if ("client_credentials".equals(request.getGrantType())) {
            //覆盖OAuth2Request
            OAuth2Request newRequest = new OAuth2Request(request.getRequestParameters(),
                    request.getClientId() , list, request.isApproved(),
                    request.getScope(), request.getResourceIds(), request.getRedirectUri(),
                    request.getResponseTypes(), request.getExtensions());
            return new OAuth2Authentication(newRequest, null);
        }
        TokenPrincipal principal = (TokenPrincipal) userAuthentication.getPrincipal();

        LambdaQueryWrapper<EntityAccountDTO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EntityAccountDTO::getAccountId, aid);

        EntityAccountDTO entity = entityAccountService.getOne(wrapper);
        if (entity != null) {
            principal.getPrincipal().put("entityId", entity.getEntityId());
        }
        //重新封装 OAuth2Authentication
        Authentication userAuth = new UsernamePasswordAuthenticationToken(principal, null, list);
        return new OAuth2Authentication(request, userAuth);
    }
}
